home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / oleo130s.zip / OLEO130S.TAR / oleo-1.3 / graph.c < prev    next >
C/C++ Source or Header  |  1993-03-30  |  27KB  |  1,255 lines

  1. /*    Copyright (C) 1993 Free Software Foundation, Inc.
  2.  
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7.  
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. GNU General Public License for more details.
  12.  
  13. You should have received a copy of the GNU General Public License
  14. along with this software; see the file COPYING.  If not, write to
  15. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  16.  
  17.  
  18.  
  19. #include <ctype.h>
  20. #include "global.h"
  21. #include "graph.h"
  22. #include "cmd.h"
  23. #include "line.h"
  24. #include "io-term.h"
  25. #include "info.h"
  26. #include "cell.h"
  27. #include "regions.h"
  28. #include "ref.h"
  29. #include "io-utils.h"
  30.  
  31. /* Parameters for the next graph that will be drawn. */
  32.  
  33. /* This determines the type and destination of the ouput.
  34.  * It should be the argument to a  `set term %s'.  For posctscript graphs,
  35.  * we slip in a `set output %s' as well.
  36.  */
  37. static struct line graph_term_cmd;
  38. static struct line graph_output_file;
  39.  
  40. #ifdef __STDC__
  41. typedef void (*plotter) (void);
  42. #else
  43. typedef void (*plotter) ();
  44. #endif
  45.  
  46. struct get_symbols_frame;
  47. struct write_data_frame;
  48. #ifdef __STDC__
  49. static void get_symbols_thunk (struct get_symbols_frame * fr,
  50.                    CELL * cell, CELLREF r, CELLREF c);
  51. static void write_data_thunk (struct write_data_frame * fr,
  52.                   CELL * y_cell, CELLREF r, CELLREF c) ;
  53. static void spew_gnuplot (FILE  * fp, struct line * data_files, char * dir,
  54.               char * dbase); 
  55. static void spew_for_x (void);
  56. static void spew_for_ps (void);
  57. #else
  58. static void get_symbols_thunk ();
  59. static void write_data_thunk ();
  60. static void spew_gnuplot ();
  61. static void spew_for_x ();
  62. static void spew_for_ps ();
  63. #endif
  64.  
  65. static plotter plot_fn = 0;
  66.  
  67. char * gnuplot_program = "gnuplot";
  68. char * gnuplot_shell = "/bin/sh";
  69. char * rm_program = "/bin/rm";
  70.  
  71. char * graph_axis_name [graph_num_axis] =
  72. {
  73.   "x", "y"
  74. };
  75.  
  76. char *
  77. graph_order_name [graph_num_orders] =
  78. {
  79.   "rows",
  80.   "columns",
  81. };
  82.  
  83. char *graph_pair_order_name[graph_num_pair_orders] =
  84. {
  85.   "rows of hz pairs",
  86.   "rows of vt pairs",
  87.   "enumerated rows",
  88.   "cols of hz pairs",
  89.   "cols of vt pairs",
  90.   "enumerated cols"
  91. };
  92.  
  93. int graph_ornt_row_magic [graph_num_pair_orientations] = { 0, 1, 0 };
  94. int graph_ornt_col_magic [graph_num_pair_orientations] = { 1, 0, 0 };
  95.  
  96.  
  97. /* `set label %s' for each axis.
  98.  */
  99. static struct line graph_axis_title [graph_num_axis];
  100.  
  101. /* set logarithmic */
  102. static int graph_logness [graph_num_axis];
  103.  
  104. /* Arguments to `set range [%s:%s]' */
  105. static struct line graph_rng_lo [graph_num_axis];
  106. static struct line graph_rng_hi [graph_num_axis];
  107.  
  108. /* The ranges (if any) of the symbolic names
  109.  * for integer coordinates starting at 0.
  110.  * If none, these will have lr == NON_ROW.
  111.  */
  112. static struct rng graph_axis_symbols [graph_num_axis];
  113. static enum graph_ordering graph_axis_ordering [graph_num_axis];
  114.  
  115. /* Names to print along the axes */
  116. static struct rng graph_axis_labels [graph_num_axis];
  117. static enum graph_pair_ordering graph_axis_label_order [graph_num_axis];
  118.  
  119. /* Parameters for each dataset. */
  120. #define NUM_DATASETS 10
  121.  
  122. /* plot .... with %s */
  123. static struct line graph_style [NUM_DATASETS];
  124. static struct line graph_title [NUM_DATASETS];
  125. static struct rng graph_data [NUM_DATASETS];
  126. static enum graph_pair_ordering graph_data_order [graph_num_axis];
  127.  
  128.  
  129.  
  130.  
  131. #ifdef __STDC__
  132. enum graph_axis
  133. chr_to_axis (int c)
  134. #else
  135. enum graph_axis
  136. chr_to_axis (c)
  137.      int c;
  138. #endif
  139. {
  140.   c = tolower (c);
  141.   switch (c)
  142.     {
  143.     case 'x':
  144.       return graph_x;
  145.     case 'y':
  146.       return graph_y;
  147.     }
  148.   io_error_msg ("Unkown graph-axis `%c' (try `x' or `y')", c);
  149.   return graph_x;        /* not reached, actualy. */
  150. }
  151.  
  152.  
  153. #ifdef __STDC__
  154. enum graph_ordering
  155. chr_to_graph_ordering (int c)
  156. #else
  157. enum graph_ordering
  158. chr_to_graph_ordering (c)
  159.      int c;
  160. #endif
  161. {
  162.   c = tolower (c);
  163.   switch (c)
  164.     {
  165.     case 'r':
  166.       return graph_rows;
  167.     case 'c':
  168.       return graph_cols;
  169.     }
  170.   io_error_msg ("Unknown cell ordering `%c' (try `r' or `c').", c);
  171.   return graph_rows;        /* not reached */
  172. }
  173.  
  174. #ifdef __STDC__
  175. enum graph_pair_ordering
  176. chrs_to_graph_pair_ordering (int pair, int dir)
  177. #else
  178. enum graph_pair_ordering
  179. chrs_to_graph_pair_ordering (pair, dir)
  180.      int pair;
  181.      int dir;
  182. #endif
  183. {
  184.   int pair_offset;
  185.   pair = tolower (pair);
  186.   dir = tolower (dir);
  187.  
  188.   switch (pair)
  189.     {
  190.     case 'h':
  191.       pair_offset = graph_hz;
  192.       break;
  193.     case 'v':
  194.       pair_offset = graph_vt;
  195.       break;
  196.     case 'i':
  197.       pair_offset = graph_implicit;
  198.       break;
  199.     default:
  200.       pair_offset = graph_implicit;
  201.       io_error_msg
  202.     ("graph.c: invalid pair ording `%c' (wanted h, v, or i)", pair);
  203.       /* no deposit... */
  204.     }
  205.  
  206.   return PAIR_ORDER(chr_to_graph_ordering (dir), pair_offset);
  207. }
  208.  
  209. #ifdef __STDC__
  210. char *
  211. graph_quoted_str (char *str)
  212. #else
  213. char *
  214. graph_quoted_str (str)
  215.      char *str;
  216. #endif
  217. {
  218.   static struct line buf;
  219.   
  220.   set_line (&buf, "\"");
  221.   while (*str)
  222.     {
  223.       switch (*str)
  224.     {
  225.     case '"':
  226.       catn_line (&buf, "\\\"", 2);
  227.       break;
  228.     default:
  229.       catn_line (&buf, str, 1);
  230.       break;
  231.     }
  232.       ++str;
  233.     }
  234.   catn_line (&buf, "\"", 1);
  235.   return buf.buf;
  236. }
  237.  
  238.  
  239.  
  240. #ifdef __STDC__
  241. void
  242. graph_x11_mono (void)
  243. #else
  244. void
  245. graph_x11_mono ()
  246. #endif
  247. {
  248.   set_line (&graph_term_cmd, "x11 # b/w");
  249.   set_line (&graph_output_file, "");
  250.   plot_fn = spew_for_x;
  251. }
  252.  
  253.  
  254. #ifdef __STDC__
  255. void
  256. graph_x11_color (void)
  257. #else
  258. void
  259. graph_x11_color ()
  260. #endif
  261. {
  262.   set_line (&graph_term_cmd, "X11 # color");
  263.   set_line (&graph_output_file, "");
  264.   plot_fn = spew_for_x;
  265. }
  266.  
  267.  
  268. #ifdef __STDC__
  269. void
  270. graph_postscript (char * file, int kind, int spectrum, char * font, int pt_size)
  271. #else
  272. void
  273. graph_postscript (file, kind, spectrum, font, pt_size)
  274.      char * file;
  275.      int kind;
  276.      int spectrum;
  277.      char * font;
  278.      int pt_size;
  279. #endif
  280. {
  281.   kind = tolower (kind);
  282.   spectrum = tolower (spectrum);
  283.   if (!index ("led", kind))
  284.     io_error_msg
  285.       ("Incorrect postscript graph type %c (should be one of l, e, or c)",
  286.        kind);
  287.   if (!index ("mc", spectrum))
  288.     io_error_msg
  289.       ("Incorrect postscript color type %c (should be either m or c)",
  290.        spectrum);
  291.   sprint_line (&graph_term_cmd,
  292.            "postscript %c %c %s %d  # Postscript",
  293.            kind, spectrum, graph_quoted_str (font), pt_size);
  294.   set_line (&graph_output_file, file);
  295.   plot_fn = spew_for_ps;
  296. }
  297.  
  298.  
  299.  
  300. #ifdef __STDC__
  301. void
  302. graph_set_axis_title (int axis_c, char * title)
  303. #else
  304. void
  305. graph_set_axis_title (axis_c, title)
  306.      int axis_c;
  307.      char * title;
  308. #endif
  309. {
  310.   enum graph_axis axis = chr_to_axis (axis_c);
  311.   set_line (&graph_axis_title [axis], graph_quoted_str (title));
  312. }
  313.  
  314. #ifdef __STDC__
  315. void
  316. graph_set_logness (int axis_c, int explicit, int newval)
  317. #else
  318. void
  319. graph_set_logness (axis_c, explicit, newval)
  320.      int axis_c;
  321.      int explicit;
  322.      int newval;
  323. #endif
  324. {
  325.   enum graph_axis axis = chr_to_axis (axis_c);
  326.   static struct line msg_buf;
  327.  
  328.   if (!explicit)
  329.     newval = !graph_logness [axis];
  330.   else
  331.     newval = (newval > 0);
  332.  
  333.   graph_logness [axis] = newval;
  334.   sprint_line (&msg_buf, "%slogarithmic %s%s",
  335.            ((graph_logness [graph_x] || graph_logness [graph_y])
  336.         ? "" : "no"),
  337.            graph_logness [graph_x] ? "x" : "",
  338.            graph_logness [graph_y] ? "y" : "");
  339.   io_info_msg ("set %s", msg_buf.buf);
  340. }
  341.  
  342. #ifdef __STDC__
  343. void
  344. graph_check_range (char * val)
  345. #else
  346. void
  347. graph_check_range (val)
  348.      char * val;
  349. #endif
  350. {
  351.   if (says_default (val))
  352.     return;
  353.   while (isspace (*val)) ++val;
  354.   if (*val == '-') ++val;
  355.   while (isspace (*val)) ++val;
  356.   if (!isdigit (*val))
  357.     io_error_msg
  358.       ("Illegal range specifier %s (should be a numer or `def').", val);
  359.   else
  360.     {
  361.       while (*val)
  362.     if (isspace (*val) || isdigit (*val))
  363.       ++val;
  364.     else
  365.       break;
  366.       while (isspace (*val)) ++val;
  367.       if (*val == '.') ++val;
  368.       while (*val)
  369.     if (isspace (*val) || isdigit (*val))
  370.       ++val;
  371.     else
  372.       io_error_msg
  373.         ("Illegal range specifier %s (should be a numer or `def').", val);
  374.     }
  375.         
  376. }
  377.  
  378.  
  379. #ifdef __STDC__
  380. void
  381. graph_set_axis_lo (int axis_c, char * val)
  382. #else
  383. void
  384. graph_set_axis_lo (axis_c, val)
  385.      int axis_c;
  386.      char * val;
  387. #endif
  388. {
  389.   enum graph_axis axis = chr_to_axis (axis_c);
  390.   graph_check_range (val);
  391.   set_line (&graph_rng_lo [axis], val);
  392.   graph_axis_symbols [axis].lr = NON_ROW;
  393. }
  394.  
  395.  
  396. #ifdef __STDC__
  397. void
  398. graph_set_axis_hi (int axis_c, char * val)
  399. #else
  400. void
  401. graph_set_axis_hi (axis_c, val)
  402.      int axis_c;
  403.      char * val;
  404. #endif
  405. {
  406.   enum graph_axis axis = chr_to_axis (axis_c);
  407.   graph_check_range (val);
  408.   set_line (&graph_rng_hi [axis], val);
  409.   graph_axis_symbols [axis].lr = NON_ROW;
  410. }
  411.  
  412. #ifdef __STDC__
  413. void
  414. graph_set_axis_symbolic (int axis_c, struct rng * rng, int ordering_c) 
  415. #else
  416. void
  417. graph_set_axis_symbolic (axis_c, rng, ordering_c)
  418.      int axis_c;
  419.      struct rng * rng;
  420.      int ordering_c;
  421. #endif
  422. {
  423.   enum graph_axis axis = chr_to_axis (axis_c);
  424.   enum graph_ordering ordering = chr_to_graph_ordering (ordering_c);
  425.   int top = (rng->hr - rng->lr + 1) * (rng->hc - rng->lc + 1) - 1;
  426.   char buf [64];
  427.  
  428.   sprintf (buf, "%d.5", top);
  429.   graph_set_axis_lo (axis, "-0.5");
  430.   graph_set_axis_hi (axis, buf);
  431.   graph_axis_symbols [axis] = *rng;
  432.   graph_axis_ordering [axis] = ordering;
  433. }
  434.  
  435. #ifdef __STDC__
  436. void
  437. graph_set_axis_labels (int axis_c, struct rng * rng, int pair, int dir)
  438. #else
  439. void
  440. graph_set_axis_labels (axis_c, rng, dir, pair)
  441.      int axis_c;
  442.      struct rng * rng;
  443.      int pair;
  444.      int dir;
  445. #endif
  446. {
  447.   enum graph_pair_ordering order = chrs_to_graph_pair_ordering (pair, dir);
  448.   enum graph_axis axis = chr_to_axis (axis_c);
  449.   graph_axis_labels [axis] = *rng;
  450.   graph_axis_label_order [axis] = order;
  451. }
  452.  
  453. #ifdef __STDC__
  454. void
  455. graph_default_axis_labels (int axis_c)
  456. #else
  457. void
  458. graph_default_axis_labels (axis_c)
  459.      int axis_c;
  460. #endif
  461. {
  462.   enum graph_axis axis = chr_to_axis (axis_c);
  463.   graph_axis_labels [axis].lr = NON_ROW;
  464. }
  465.  
  466.  
  467.  
  468. static char * graph_plot_styles [] =
  469. {
  470.   "lines",
  471.   "points",
  472.   "linespoints",
  473.   "impulses",
  474.   "dots",
  475.    0
  476. };
  477.  
  478. #ifdef __STDC__
  479. int
  480. graph_check_style (char * name)
  481. #else
  482. int
  483. graph_check_style (name)
  484.      char * name;
  485. #endif
  486. {
  487.   int x =
  488.     words_member (graph_plot_styles, parray_len (graph_plot_styles), name);
  489.   if (x < 0)
  490.     io_error_msg
  491.       ("Invalid line style %s. (Try M-x describe-function set-graph-style).");
  492.   return x;
  493. }
  494.  
  495.  
  496. #ifdef __STDC__
  497. void
  498. graph_set_style (int data_set, char * style)
  499. #else
  500. void
  501. graph_set_style (data_set, style)
  502.      int data_set;
  503.      char * style;
  504. #endif
  505. {
  506.   int x = graph_check_style (style);
  507.   if ((data_set < 0) || (data_set >= NUM_DATASETS))
  508.     io_error_msg
  509.       ("set-graph-style -- data-set out of range: %d (should be in [0..%d])",
  510.        data_set, NUM_DATASETS);
  511.   set_line (&graph_style [data_set], graph_plot_styles [x]);
  512. }
  513.  
  514. #ifdef __STDC__
  515. void
  516. graph_set_data_title (int data_set, char * title)
  517. #else
  518. void
  519. graph_set_data_title (data_set, title)
  520.      int data_set;
  521.      char * title;
  522. #endif
  523. {
  524.   if ((data_set < 0) || (data_set >= NUM_DATASETS))
  525.     io_error_msg
  526.       ("set-graph-title -- data-set out of range: %d (should be in [0..%d])",
  527.        data_set, NUM_DATASETS);
  528.   set_line (&graph_title [data_set], title);
  529. }
  530.  
  531. #ifdef __STDC__
  532. void
  533. graph_set_data (int data_set, struct rng * rng, int pair, int dir)
  534. #else
  535. void
  536. graph_set_data (data_set, rng, pair, dir)
  537.      int data_set;
  538.      struct rng * rng;
  539.      int pair;
  540.      int dir;
  541. #endif
  542. {
  543.   enum graph_pair_ordering order = chrs_to_graph_pair_ordering (pair, dir);
  544.   if ((data_set < 0) || (data_set >= NUM_DATASETS))
  545.     io_error_msg
  546.       ("set-graph-data -- data-set out of range: %d (should be in [0..%d])",
  547.        data_set, NUM_DATASETS);
  548.   graph_data [data_set] = *rng;
  549.   graph_data_order [data_set] = order;
  550. }
  551.  
  552.  
  553.  
  554.  
  555. #ifdef __STDC__
  556. void
  557. graph_presets (void)
  558. #else
  559. void
  560. graph_presets ()
  561. #endif
  562. {
  563.   if (using_curses)
  564.     graph_postscript ("#plot.ps", 'd', 'm', "TimesRoman", 12);
  565.   else
  566.     graph_x11_mono ();
  567.   {
  568.     enum graph_axis axis;
  569.     for (axis = graph_x; axis < graph_num_axis; ++axis)
  570.       {
  571.     int axis_c = graph_axis_name [axis][0];
  572.     graph_logness [axis] = 0;
  573.     graph_set_axis_title (axis_c, "");
  574.     graph_set_axis_lo (axis_c, "def");
  575.     graph_set_axis_hi (axis_c, "def");
  576.     graph_set_axis_title (axis_c, "");
  577.     graph_default_axis_labels (axis_c);
  578.       }
  579.   }
  580. }
  581.  
  582.  
  583.  
  584.  
  585.  
  586. #ifdef __STDC__
  587. void
  588. graph_clear_datasets (void)
  589. #else
  590. void
  591. graph_clear_datasets ()
  592. #endif
  593. {
  594.   int x;
  595.   for (x = 0; x < NUM_DATASETS; ++x)
  596.     {
  597.       graph_set_style (x, "lines");
  598.       graph_set_data_title (x, "");
  599.       graph_data [x].lr = NON_ROW;
  600.     }
  601. }
  602.  
  603.  
  604. #ifdef __STDC__
  605. void
  606. init_graphing (void)
  607. #else
  608. void
  609. init_graphing ()
  610. #endif
  611. {
  612.   gnuplot_program = getenv ("GNUPLOT_PROG");
  613.   if (!gnuplot_program)
  614.     gnuplot_program = "gnuplot";
  615.   gnuplot_shell = getenv ("GNUPLOT_SHELL");
  616.   if (!gnuplot_shell)
  617.     gnuplot_shell = "/bin/sh";
  618.   rm_program = getenv ("RM_PROG");
  619.   if (!rm_program)
  620.     rm_program = "/bin/rm";
  621.   graph_presets ();
  622.   graph_clear_datasets ();
  623. }
  624.  
  625.  
  626. #ifdef __STDC__
  627. void
  628. graph_make_info (void)
  629. #else
  630. void
  631. graph_make_info ()
  632. #endif
  633. {
  634.   struct info_buffer * ib = find_or_make_info ("graphing-parameters");
  635.   enum graph_axis axis;
  636.  
  637.   clear_info (ib);
  638.  
  639.   {
  640.     print_info
  641.       (ib,
  642.        "");
  643.     print_info
  644.       (ib,
  645.        "Parameter        Value");
  646.     print_info
  647.       (ib,
  648.        "");
  649.  
  650.     print_info
  651.       (ib,
  652.        "output type        %s",
  653.        graph_term_cmd.buf);
  654.   }
  655.  
  656.   if (graph_output_file.buf[0])
  657.     print_info
  658.       (ib,
  659.        "output file        %s",
  660.        graph_output_file.buf);
  661.   
  662.   for (axis = graph_x; axis <= graph_y; ++axis)
  663.     print_info
  664.       (ib,
  665.        "%s-axis title        %s",
  666.        graph_axis_name [axis], graph_axis_title[axis].buf);
  667.  
  668.   {
  669.     print_info
  670.       (ib,
  671.        "logarithmic axes    %s",
  672.        (graph_logness [graph_x]
  673.     ? (graph_logness [graph_y] ? "x,y" : "x")
  674.     : (graph_logness [graph_y] ? "y" : "-neither-")));
  675.  
  676.   }
  677.   for (axis = graph_x; axis <= graph_y; ++axis)
  678.     {
  679.       if (graph_axis_symbols[axis].lr != NON_ROW)
  680.     print_info
  681.       (ib,
  682.            "%s-axis symbols    %s in %s",
  683.        graph_axis_name [axis],
  684.        graph_order_name [graph_axis_ordering [axis]],
  685.        range_name (&graph_axis_symbols [axis]));
  686.       else
  687.     print_info
  688.       (ib,
  689.         "%s-axis range        [%s..%s]",
  690.        graph_axis_name [axis],
  691.        graph_rng_lo [axis].buf, graph_rng_hi [axis].buf,
  692.        graph_rng_hi [axis].buf, graph_rng_hi [axis].buf);
  693.     }
  694.  
  695.   for (axis = graph_x; axis <= graph_y; ++axis)
  696.     {
  697.       if (graph_axis_labels[axis].lr != NON_ROW)
  698.     print_info
  699.       (ib,
  700.            "%s-axis labels        %s in %s",
  701.        graph_axis_name [axis],
  702.        graph_pair_order_name [graph_axis_label_order [axis]],
  703.        range_name (&graph_axis_labels [axis]));
  704.     }
  705.  
  706.   {
  707.     int x;
  708.     for (x = 0; x < NUM_DATASETS; ++x)
  709.       if (graph_data [x].lr != NON_ROW)
  710.       {
  711.     print_info (ib, "");
  712.     print_info (ib,"Data Set %d%s%s",
  713.             x,
  714.             graph_title[x].buf[0] ? " entitled " : "",
  715.             graph_title[x].buf);
  716.     print_info (ib,"  data for this set: %s in %s",
  717.             graph_pair_order_name [graph_data_order [x]],
  718.             range_name (&graph_data[x]));
  719.     print_info (ib,"  style for this set: %s",
  720.             graph_style[x].buf);
  721.     print_info (ib,"");
  722.       }
  723.   }
  724. }
  725.  
  726.  
  727.  
  728. #ifdef __STDC__
  729. static FILE *
  730. mk_tmp_file (struct line * line, char * dir, char * base)
  731. #else
  732. static FILE *
  733. mk_tmp_file (line, dir, base)
  734.      struct line * line;
  735.      char * dir;
  736.      char * base;
  737. #endif
  738. {
  739.   set_line (line, tempnam (dir, base));
  740.   return fopen (line->buf, "w");
  741. }
  742.  
  743.  
  744. #ifdef __STDC__
  745. void
  746. for_pairs_in (struct rng * rng, enum graph_pair_ordering order, fpi_thunk thunk, void * frame)
  747. #else
  748. void
  749. for_pairs_in (rng, order, thunk, frame)
  750.      struct rng * rng;
  751.      enum graph_pair_ordering order;
  752.      fpi_thunk thunk;
  753.      void * frame;
  754. #endif
  755. {
  756.   CELLREF r;
  757.   CELLREF c;
  758.   enum graph_pair_orientation ornt = order % graph_num_pair_orientations;
  759.   enum graph_ordering dir = ORDER_OF_PAIRS(order);
  760.   int r_inc = 1 + graph_ornt_row_magic [ornt];
  761.   int c_inc = 1 + graph_ornt_col_magic [ornt];
  762.   if (dir == graph_rows)
  763.     {
  764.       r = rng->lr;
  765.       while (1)
  766.     {
  767.       c = rng->lc;
  768.       while (1)
  769.         {
  770.           CELLREF y_r = r + graph_ornt_row_magic [ornt];
  771.           CELLREF y_c = c + graph_ornt_col_magic [ornt];
  772.           CELL * cell = find_cell (y_r, y_c);
  773.           thunk (frame, cell, y_r, y_c);
  774.           if ((rng->hc - c) < c_inc)
  775.         break;
  776.           c += c_inc;
  777.         }
  778.       if ((rng->hr - r) < r_inc)
  779.         break;
  780.       r += r_inc;
  781.     }
  782.     }
  783.   else
  784.     {
  785.       c = rng->lc;
  786.       while (1)
  787.     {
  788.       r = rng->lr;
  789.       while (1)
  790.         {
  791.           CELLREF y_r = r + graph_ornt_row_magic [ornt];
  792.           CELLREF y_c = c + graph_ornt_col_magic [ornt];
  793.           CELL * cell = find_cell (y_r, y_c);
  794.           thunk (frame, cell, y_r, y_c);
  795.           if ((rng->hr - r) < r_inc)
  796.         break;
  797.           r += r_inc;
  798.         }
  799.       if ((rng->hc - c) < c_inc)
  800.         break;
  801.       c += c_inc;
  802.     }
  803.     }
  804. }
  805.  
  806. struct write_tics_frame
  807. {
  808.   FILE * fp;
  809.   enum graph_axis axis;
  810.   enum graph_pair_orientation ornt;
  811.   int tic_cnt;
  812. };
  813.  
  814. #ifdef __STDC__
  815. static void
  816. write_tics_thunk (struct write_tics_frame * fr, CELL * cp, CELLREF r, CELLREF c)
  817. #else
  818. static void
  819. write_tics_thunk (fr, cp, r, c)
  820.      struct write_tics_frame * fr;
  821.      CELL * cp;
  822.      CELLREF r;
  823.      CELLREF c;
  824. #endif
  825. {
  826.   char * str = graph_quoted_str (print_cell (cp));
  827.   if (fr->tic_cnt)
  828.     fputs (", ", fr->fp);
  829.   fprintf (fr->fp, "%s ", str);
  830.   if (fr->ornt == graph_implicit)
  831.     fprintf (fr->fp, "%d", fr->tic_cnt);
  832.   else
  833.     {
  834.       CELLREF x_r = r - graph_ornt_row_magic [fr->ornt];
  835.       CELLREF x_c = c - graph_ornt_col_magic [fr->ornt];
  836.       
  837.       fprintf (fr->fp, "%s", print_cell (find_cell (x_r, x_c)));
  838.     }
  839.   ++fr->tic_cnt;
  840. }
  841.  
  842.  
  843. #ifdef __STDC__
  844. static void
  845. write_tics_command (FILE * fp, enum graph_axis axis, struct rng * rng, enum graph_pair_ordering order)
  846. #else
  847. static void
  848. write_tics_command (fp, axis, rng, order)
  849.      FILE * fp;
  850.      enum graph_axis axis;
  851.      struct rng * rng;
  852.      enum graph_pair_ordering order;
  853. #endif
  854. {
  855.   struct write_tics_frame fr;
  856.   fr.fp = fp;
  857.   fr.axis = axis;
  858.   fr.tic_cnt = 0;
  859.   fr.ornt = order % graph_num_pair_orientations;
  860.   fprintf (fp, "set %stics (", graph_axis_name[axis]);
  861.   for_pairs_in (rng, order, (fpi_thunk)write_tics_thunk, &fr);
  862.   fputs (")\n", fp);
  863. }
  864.  
  865. struct get_symbols_frame
  866. {
  867.   int symbols;
  868.   char ** names;
  869. };
  870.  
  871. #ifdef __STDC__
  872. static void
  873. get_symbols_thunk (struct get_symbols_frame * fr,
  874.            CELL * cell, CELLREF r, CELLREF c)
  875. #else
  876. static void
  877. get_symbols_thunk (fr, cell, r, c)
  878.      struct get_symbols_frame * fr;
  879.      CELL * cell;
  880.      CELLREF r;
  881.      CELLREF c;
  882. #endif
  883. {
  884.   fr->names = (char **)ck_realloc (fr->names,
  885.                    (fr->symbols + 1) * sizeof (char *));
  886.   fr->names [fr->symbols] = ck_savestr (print_cell (cell));
  887.   ++fr->symbols;
  888. }
  889.  
  890.  
  891. struct write_data_frame
  892. {
  893.   FILE * fp;
  894.   enum graph_pair_ordering ornt;
  895.   int data_cnt;
  896.   struct get_symbols_frame gsf;
  897. };
  898.  
  899. #ifdef __STDC__
  900. static void
  901. write_data_thunk (struct write_data_frame * fr,
  902.           CELL * y_cell, CELLREF r, CELLREF c) 
  903. #else
  904. static void
  905. write_data_thunk (fr, y_cell, r, c)
  906.      struct write_data_frame * fr;
  907.      CELL * y_cell;
  908.      CELLREF r;
  909.      CELLREF c;
  910. #endif
  911. {
  912.   if (!y_cell || !GET_TYP(y_cell))
  913.     return;
  914.   if (fr->ornt == graph_implicit)
  915.     fprintf (fr->fp, "%d ", fr->data_cnt);
  916.   else
  917.     {
  918.       CELLREF x_r = r - graph_ornt_row_magic [fr->ornt];
  919.       CELLREF x_c = c - graph_ornt_col_magic [fr->ornt];
  920.       CELL * x_cell = find_cell (x_r, x_c);
  921.       if (x_cell && GET_TYP(x_cell))
  922.     {
  923.       if (graph_axis_symbols [graph_x].lr == NON_ROW)
  924.         fprintf (fr->fp, "%s ", print_cell (x_cell));
  925.       else
  926.         {
  927.           char * key = print_cell (x_cell);
  928.           int x;
  929.           for (x = 0; x < fr->gsf.symbols; ++x)
  930.         if (stricmp (key, fr->gsf.names[x]))
  931.           {
  932.             fprintf (fr->fp, "%d ", x);
  933.             break;
  934.           }
  935.         }
  936.     }
  937.     }
  938.   fprintf (fr->fp, " %s\n", print_cell (y_cell));
  939.   ++fr->data_cnt;
  940. }
  941.  
  942.  
  943. #ifdef __STDC__
  944. static void
  945. spew_gnuplot (FILE  * fp, struct line * data_files, char * dir, char * dbase)
  946. #else
  947. static void
  948. spew_gnuplot (fp, data_files, dir, dbase)
  949.      FILE  * fp;
  950.      struct line * data_files;
  951.      char * dir;
  952.      char * dbase;
  953. #endif
  954. {
  955.   fprintf (fp, "set terminal %s\n", graph_term_cmd.buf);
  956.   fprintf (fp, "set output %s\n",
  957.        (graph_output_file.buf[0]
  958.         ? graph_quoted_str (graph_output_file.buf)
  959.         : ""));
  960.  
  961.   {
  962.     enum graph_axis axis;
  963.     for (axis = graph_x; axis <= graph_y; ++axis)
  964.       {
  965.     fprintf (fp, "set %slabel %s\n", graph_axis_name[axis],
  966.          (graph_axis_title[axis].buf[0]
  967.           ? graph_axis_title[axis].buf
  968.           : ""));
  969.  
  970.     fprintf (fp, "set %srange [%s:%s]\n",
  971.          graph_axis_name [axis],
  972.          (says_default (graph_rng_lo [axis].buf)
  973.           ? ""
  974.           : graph_rng_lo[axis].buf),
  975.          (says_default (graph_rng_hi [axis].buf)
  976.           ? ""
  977.           : graph_rng_hi[axis].buf));
  978.     if (   (graph_axis_symbols [axis].lr != NON_ROW)
  979.         && (graph_axis_labels [axis].lr == NON_ROW))
  980.       write_tics_command (fp, axis, &graph_axis_symbols [axis],
  981.                   PAIR_ORDER(graph_axis_ordering[axis],
  982.                            graph_implicit));
  983.     else if (graph_axis_labels [axis].lr != NON_ROW)
  984.       write_tics_command (fp, axis,
  985.                   &graph_axis_labels [axis],
  986.                   graph_axis_label_order [axis]);
  987.     else
  988.       fprintf (fp, "set %stics\n", graph_axis_name [axis]);
  989.       }
  990.     if (!(graph_logness[graph_x] && graph_logness[graph_y]))
  991.       fprintf (fp, "set nolog %s%s\n",
  992.            graph_logness[graph_x] ? "" : "x",
  993.            graph_logness[graph_y] ? "" : "y");
  994.  
  995.     if (graph_logness[graph_x] || graph_logness[graph_y])
  996.       fprintf (fp, "set log %s%s\n",
  997.            graph_logness[graph_x] ? "x" : "",
  998.            graph_logness[graph_y] ? "y" : "");
  999.   }
  1000.   {
  1001.     int need_comma = 0;
  1002.     int x;
  1003.     fprintf (fp, "plot ");
  1004.     for (x = 0; x < NUM_DATASETS; ++x)
  1005.       {
  1006.     init_line (&data_files [x]);
  1007.     if (graph_data [x].lr != NON_ROW)
  1008.       {
  1009.         FILE * df = mk_tmp_file (&data_files [x], dir, dbase);
  1010.         struct write_data_frame wdf;
  1011.         if (!df)
  1012.           {
  1013.         /* a small core leak here... */
  1014.         io_error_msg ("Error opening temp file `%s' for graph data.",
  1015.                   data_files [x].buf);
  1016.           }
  1017.         wdf.fp = df;
  1018.         wdf.ornt = graph_data_order [x] % graph_num_pair_orientations;
  1019.         wdf.data_cnt = 0;
  1020.         wdf.gsf.symbols = 0;
  1021.         wdf.gsf.names = 0;
  1022.         if (graph_axis_symbols [graph_x].lr != NON_ROW)
  1023.           for_pairs_in (&graph_axis_symbols [graph_x],
  1024.                 PAIR_ORDER (graph_axis_ordering [graph_x],
  1025.                     graph_implicit),
  1026.                 (fpi_thunk)get_symbols_thunk,
  1027.                 &wdf.gsf);
  1028.         for_pairs_in (&graph_data [x], graph_data_order [x],
  1029.               (fpi_thunk)write_data_thunk, &wdf);
  1030.         if (graph_axis_symbols [graph_x].lr != NON_ROW)
  1031.           {
  1032.         int x;
  1033.         for (x = 0; x < wdf.gsf.symbols; ++x)
  1034.           free (wdf.gsf.names[x]);
  1035.         ck_free (wdf.gsf.names);
  1036.           }
  1037.         fprintf (fp, "%s %s %s with %s",
  1038.              need_comma ? "," : "",
  1039.              graph_quoted_str (data_files [x].buf),
  1040.              graph_title [x].buf,
  1041.              graph_style [x].buf);
  1042.         need_comma = 1;
  1043.         fclose (df);
  1044.       }
  1045.       }
  1046.     fprintf (fp, "\n");
  1047.   }
  1048. }
  1049.  
  1050.  
  1051. #ifdef __STDC__
  1052. static void
  1053. graph_spew_with_parameters (struct line * shell_script, struct line *
  1054.                 gp_script, char * last_cmd, char * dir, char *
  1055.                 dbase, char * gbase, char * sbase, int run_gnuplot)
  1056. #else
  1057. static void
  1058. graph_spew_with_parameters (shell_script, gp_script, last_cmd, dir, dbase,
  1059.                 gbase, sbase, run_gnuplot)
  1060.      struct line * shell_script;
  1061.      struct line * gp_script;
  1062.      char * last_cmd;
  1063.      char * dir;
  1064.      char * dbase;
  1065.      char * gbase;
  1066.      char * sbase;
  1067.      int run_gnuplot;
  1068. #endif
  1069. {
  1070.   struct line data_files [NUM_DATASETS];
  1071.   FILE * fp;
  1072.   fp = mk_tmp_file (gp_script, dir, gbase);
  1073.   if (!fp)
  1074.     {
  1075.       /* coreleak filename */
  1076.       io_error_msg ("Error opening tmp file `%s' for plot script.",
  1077.             gp_script->buf);
  1078.     }
  1079.   spew_gnuplot (fp, data_files, dir, dbase);
  1080.   if (last_cmd)
  1081.     fputs (last_cmd, fp);
  1082.   if (sbase)
  1083.     {
  1084.       FILE * shfp;
  1085.       init_line (shell_script);
  1086.       shfp = mk_tmp_file (shell_script, dir, sbase);
  1087.       fprintf (shfp, "#!%s\n", gnuplot_shell);
  1088.       fputs ("\n", shfp);
  1089.       if (run_gnuplot)
  1090.     fprintf (shfp, "%s %s\n", gnuplot_program, gp_script->buf);
  1091.       fprintf (shfp, "%s %s %s  ",
  1092.            rm_program, gp_script->buf, shell_script->buf);
  1093.       {
  1094.     int x;
  1095.     for (x = 0; x < NUM_DATASETS; ++x)
  1096.       if (data_files[x].buf)
  1097.         fprintf (shfp, "%s ", data_files [x].buf);
  1098.       }
  1099.       fputs ("\n", shfp);
  1100.       fclose (shfp);
  1101.     }
  1102.   fclose (fp);
  1103. }
  1104.  
  1105.  
  1106. static FILE * pipe_to_gnuplot = 0;
  1107. static char * cleanup_script = 0;
  1108. static char * gnuplot_script = 0;
  1109.  
  1110. #ifdef __STDC__
  1111. static void death_to_gnuplot (void);
  1112. #else
  1113. static void death_to_gnuplot ();
  1114. #endif
  1115.  
  1116. #ifdef __STDC__
  1117. static void
  1118. gnuplot_exception (int fd)
  1119. #else
  1120. static void
  1121. gnuplot_exception (fd)
  1122.      int fd;
  1123. #endif
  1124. {
  1125.   death_to_gnuplot ();
  1126. }
  1127.  
  1128. #ifdef __STDC__
  1129. static void
  1130. gnuplot_writable (int fd)
  1131. #else
  1132. static void
  1133. gnuplot_writable (fd)
  1134.      int fd;
  1135. #endif
  1136. {
  1137.   FD_CLR (fd, &write_fd_set);
  1138.   file_write_hooks [fd].hook_fn = 0;
  1139.   fprintf (pipe_to_gnuplot, "\n\nload %s\n", graph_quoted_str (gnuplot_script));
  1140.   fflush (pipe_to_gnuplot);
  1141. }
  1142.  
  1143. #ifdef __STDC__
  1144. static void
  1145. ensure_gnuplot_pipe (void)
  1146. #else
  1147. static void
  1148. ensure_gnuplot_pipe ()
  1149. #endif
  1150. {
  1151.   if (!pipe_to_gnuplot)
  1152.     {
  1153.       pipe_to_gnuplot = popen (gnuplot_program, "w");
  1154.       if (!pipe_to_gnuplot)
  1155.     io_error_msg ("Can't popen gnuplot.");
  1156.     }
  1157.   if (gnuplot_script)
  1158.     {
  1159.       file_write_hooks [fileno (pipe_to_gnuplot)].hook_fn = gnuplot_writable;
  1160.       file_exception_hooks [fileno (pipe_to_gnuplot)].hook_fn = gnuplot_exception;
  1161.       FD_SET (fileno (pipe_to_gnuplot), &write_fd_set);
  1162.       FD_SET (fileno (pipe_to_gnuplot), &exception_fd_set);
  1163.     }
  1164. }
  1165.  
  1166. #ifdef __STDC__
  1167. static void
  1168. death_to_gnuplot (void)
  1169. #else
  1170. static void
  1171. death_to_gnuplot ()
  1172. #endif
  1173. {
  1174.   if (pipe_to_gnuplot)
  1175.     {
  1176.       int fd = fileno (pipe_to_gnuplot);
  1177.       file_write_hooks [fd].hook_fn = 0;
  1178.       file_exception_hooks [fd].hook_fn = 0;
  1179.       FD_CLR (fd, &write_fd_set);
  1180.       FD_CLR (fd, &exception_fd_set);
  1181.       pclose (pipe_to_gnuplot);
  1182.     }
  1183.   pipe_to_gnuplot = 0;
  1184.   if (cleanup_script)
  1185.     system (cleanup_script);
  1186.   if (cleanup_script)
  1187.     ck_free (cleanup_script);
  1188.   if (gnuplot_script)
  1189.     ck_free (gnuplot_script);
  1190. }
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196. #ifdef __STDC__
  1197. static void
  1198. spew_for_x (void)
  1199. #else
  1200. static void
  1201. spew_for_x ()
  1202. #endif
  1203. {
  1204.   struct line shell_script;
  1205.   struct line gp_script;
  1206.   init_line (&shell_script);
  1207.   init_line (&gp_script);
  1208.   graph_spew_with_parameters (&shell_script, &gp_script, "pause -1\n", 0,
  1209.                   "#data", "#plot", "#sh", 0);
  1210.   splicen_line (&shell_script, " ", 1, 0);
  1211.   splicen_line (&shell_script, gnuplot_shell, strlen (gnuplot_shell), 0);
  1212.   if (cleanup_script)
  1213.     {
  1214.       system (cleanup_script);
  1215.       free (cleanup_script);
  1216.     }
  1217.   cleanup_script = shell_script.buf;
  1218.   if (gnuplot_script)
  1219.     free (gnuplot_script);
  1220.   gnuplot_script = gp_script.buf;
  1221.   ensure_gnuplot_pipe ();
  1222. }
  1223.  
  1224. #ifdef __STDC__
  1225. static void
  1226. spew_for_ps (void)
  1227. #else
  1228. static void
  1229. spew_for_ps ()
  1230. #endif
  1231. {
  1232.   struct line shell_script;
  1233.   struct line gp_script;
  1234.   init_line (&shell_script);
  1235.   graph_spew_with_parameters (&shell_script, &gp_script, 0, "", "#data",
  1236.                   "#plot", "#sh", 1); 
  1237.   splicen_line (&shell_script, " ", 1, 0);
  1238.   splicen_line (&shell_script, gnuplot_shell, strlen (gnuplot_shell), 0);
  1239.   system (shell_script.buf);
  1240.   free_line (&shell_script);
  1241.   free_line (&gp_script);
  1242. }
  1243.  
  1244. #ifdef __STDC__
  1245. void
  1246. graph_plot (void)
  1247. #else
  1248. void
  1249. graph_plot ()
  1250. #endif
  1251. {
  1252.   plot_fn ();
  1253. }
  1254.  
  1255.